﻿using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using RG.Common.WPF.Commands;
using Microsoft.Practices.Unity;
using RG.Common;
using RG.Common.WPF;

namespace RG.Common.WPF.Wizard
{
    [SupportDataBinding]
    public class WizardVM : IWizardVM, IChildView
    {
        public IUnityContainer Cfg { get; set; }
        public WorkplaceWorker Worker { get; private set; }

        public ICommand NextCmd { get; set; }
        public ICommand BackCmd { get; set; }

        public string ErrorText { get; set; }

        public string NextCaption { get; set; }
        private ObservableCollection<IWizardPage> pages;


        public ObservableCollection<IWizardPage> Pages
        {
            get { return pages; }
            set
            {
                pages = value;
                foreach (var page in pages)
                    page.ParentWizardVM = this;

                Views = new ObservableCollection<object>(pages.Select(x => Cfg.CreateView(x)));
                CurrentPage = FirstPage == null ? pages[0] : Pages.Where(x => x.GetType() == FirstPage).FirstOrDefault();
            }
        }

        public ObservableCollection<object> Views { get; private set; }

        [DependOn("CurrentPage")]
        public string CurrentPageCaption
        {
            get
            {
                if (CurrentPage != null && !string.IsNullOrEmpty(CurrentPage.Caption))
                    return CurrentPage.Caption;
                return string.Empty;
            }

        }

        private Type firstPage;
        public Type FirstPage
        {
            get { return firstPage; }
            set
            {
                firstPage = value;
                if (Pages != null && Pages.Count > 0 && value != null)
                    CurrentPage = Pages.Where(x => x.GetType() == FirstPage).FirstOrDefault();
            }
        }

        private IWizardPage currentPage;
        public IWizardPage CurrentPage
        {
            get { return currentPage; }
            set
            {
                currentPage = value;
                CurrentView = Views[Pages.IndexOf(currentPage)];
                NextCaption = CurrentPage.NextCaption;
            }
        }

        public T GetCurrentPage<T>()
        {
            if (CurrentPage is T)
                return (T)CurrentPage;
            throw new ApplicationException(String.Format("Не могу преобразовать {0} к {1}", CurrentPage.GetType(), typeof(T)));
        }

        public object CurrentView { get; set; }

        public Object ResultData { get; set; }

        [InjectionConstructor]
        protected WizardVM(IUnityContainer cfg)
        {
            Cfg = cfg;
            Worker = Cfg.Resolve<WorkplaceWorker>();

            NextCaption = "Ok";

            NextCmd = new DelegateCommand(DoNext, () => CurrentPage != null && Worker.IsFree && CurrentPage.CanNext);
            BackCmd = new DelegateCommand(DoBack, () => CurrentPage != null && Worker.IsFree && CurrentPage.CanBack);
        }

        private void DoNext()
        {
            Worker.Do(
                () =>
                {
                    var pageResult = CurrentPage.Finish();

                    if (!CurrentPage.IsOutputValid)
                    {
                        ErrorText = CurrentPage.ErrorText;
                        return null;
                    }
                    ErrorText = string.Empty;

                    ResultData = pageResult;
                    var t = CurrentPage.GetNextPage();

                    IWizardPage newPage = null;
                    OnBeforeNext();
                    if (t == null)
                    {
                        var idx = Pages.IndexOf(currentPage) + 1;
                        if (idx >= 0 && idx < Pages.Count)
                            newPage = Pages[idx];
                    }
                    else
                        newPage = Pages.Where(x => x.GetType() == t).FirstOrDefault();

                    if (newPage == null) 
                        return new {newPage = (IWizardPage) null, CurrentPage};

                    newPage.Init(pageResult);
                    return new {newPage, CurrentPage};
                },
                x =>
                    {
                        if (x == null) return;
                        if (x.newPage != null) CurrentPage = x.newPage;
                        x.CurrentPage.AfterFinish();
                    });
        }

        protected virtual void OnBeforeNext()
        {

        }

        private void DoBack()
        {
            var t = CurrentPage.GetPreviousPage();
            IWizardPage newPage = null;
            if (t == null)
            {
                var idx = Pages.IndexOf(CurrentPage) - 1;
                if (idx < 0)
                    throw new ApplicationException("Однако начало");

                CurrentPage = Pages[idx];
                return;
            }

            newPage = Pages.Where(x => x.GetType() == t).FirstOrDefault();
            if (newPage == null) return;
            CurrentPage = newPage;
        }

        public object ChildView
        {
            get { return CurrentView; }
        }

        public object Child
        {
            get { return CurrentPage; }
        }

        public void SetChild<TPresenter>(TPresenter child)
        {
            throw new NotImplementedException();
        }
    }
}
